package com.aaa.gs.filter;

import com.aaa.common.util.Result;
import com.aaa.common.util.ResultStatus;
import com.aaa.gs.service.RemoteAuthService;
import com.alibaba.fastjson.JSON;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;

/**
 * ProjectName TT_car_wash_ms
 * Author 李江波
 * Date 2023/06/20 下午 04:48
 * Version 1.0.0
 * Description  单点登录过滤器
 */
@Log4j2
@Component
public class SingleLoginFilter implements GlobalFilter, Ordered {
    @Value("${white-list}") //获取配置类值，并注入到whiteList属性中
    private String whiteList;
    //定义常量,不能更改，要求前端必须再头或者请求参数中含有名称为token的参数
    @Resource
    private RemoteAuthService remoteAuthService;

    private final String REQUEST_TOKEN="token";
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //获取request和response
        ServerHttpResponse response = exchange.getResponse();
        ServerHttpRequest request = exchange.getRequest();
        //使用request对象获取请求uri
        String uri = request.getURI().getPath();
        log.info("访问的Ip为:"+uri);
        //判断白名单中是否含有请求地址  含有，直接放行
        if(whiteList.contains(uri)){
            return chain.filter(exchange);
        }
        //定义token
        String token=null;
        //获取请求中携带的token  如果获取不到，说明没有带  如果获取到  带判断是否正确
           //获取携带的token  先从herder获取
           List<String> tokenList = request.getHeaders().get(REQUEST_TOKEN);
             //判断tokenList是否为null
           if(!CollectionUtils.isEmpty(tokenList)){
                //获取token
                token=tokenList.get(0);
             }
            //再次判断token是否为空,如果依然为null 说明header没有携带 再从参数中获取
            if (token==null){
                //从参数中获取token
                MultiValueMap<String, String> queryParams = request.getQueryParams();
                //判断是否为null ，循环遍历
                if(!CollectionUtils.isEmpty(queryParams)){
                    for (Map.Entry<String, List<String>> stringListEntry : queryParams.entrySet()) {
                        String key = stringListEntry.getKey();
                        if (REQUEST_TOKEN.equals(key)){
                            List<String> valueList = stringListEntry.getValue();
                            token = valueList.get(0);
                            //找到就跳出循环，后面不用管
                            break;
                        }
                    }
                }
            }
        // 请求有问题 阻止请求继续
        //token依然为null 说明没有携带 如果携带，判断token是否正确（如果不正确提示错误，如果正确放行）
        if(token == null || !remoteAuthService.checkToken(token)){
            //定义返回Result对象
            Result result =new Result(ResultStatus.NO_AUTH_ERROR.getReturnCode(),
                    ResultStatus.NO_AUTH_ERROR.getReturnMes(),"你没有登录 滚去登录！");
            byte[] bytesMap = null;
            try {
                //把map转换为字节数组
                bytesMap = JSON.toJSONString(result).getBytes("GBK");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            //spring 提供数据缓冲类  使用response.bufferFactory()中提供的wrap方法，把字节数组转换为DataBuffer
            DataBuffer dataBuffer = response.bufferFactory().wrap(bytesMap);
            //writeWith 向响应对象中写入影响数据  需要的是Publisher接口的实现类   Mono就是该接口的实现类
            return response.writeWith(Mono.just(dataBuffer));
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        //非法Ip之后，非法字符之前
        return 8;
    }
}
